<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PNG 转 ICO 工具</title>
    <style>
        :root {
            --primary-color: #2c3e50;
            --secondary-color: #3498db;
            --success-color: #2ecc71;
            --warning-color: #f39c12;
            --danger-color: #e74c3c;
            --light-bg: #f8f9fa;
            --border-color: #dee2e6;
        }
        
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            color: var(--primary-color);
            background-color: #f5f7fa;
            line-height: 1.6;
        }
        
        .container {
            background-color: white;
            border-radius: 10px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
            padding: 30px;
            margin-top: 30px;
        }
        
        h1 {
            color: var(--primary-color);
            text-align: center;
            margin-bottom: 25px;
            font-weight: 600;
        }
        
        .intro {
            text-align: center;
            margin-bottom: 30px;
            color: #666;
        }
        
        .file-upload {
            position: relative;
            margin: 20px auto;
            width: 100%;
            max-width: 400px;
        }
        
        #fileInput {
            display: none;
        }
        
        .upload-btn {
            display: block;
            width: 100%;
            padding: 12px 20px;
            background-color: var(--secondary-color);
            color: white;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-size: 16px;
            transition: background-color 0.3s ease;
            text-align: center;
        }
        
        .upload-btn:hover {
            background-color: #2980b9;
        }
        
        #previewContainer {
            margin: 30px auto;
            text-align: center;
        }
        
        #preview {
            max-width: 200px;
            max-height: 200px;
            border-radius: 6px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            display: none;
        }
        
        #downloadLink {
            display: none;
            margin: 20px auto;
            padding: 12px 24px;
            background-color: var(--success-color);
            color: white;
            text-decoration: none;
            border-radius: 6px;
            font-weight: 500;
            transition: background-color 0.3s ease;
            text-align: center;
            max-width: 200px;
        }
        
        #downloadLink:hover {
            background-color: #27ae60;
        }
        
        .quick-actions {
            margin: 25px 0;
            text-align: center;
        }
        
        #quickConvertBtn {
            padding: 10px 20px;
            background-color: var(--warning-color);
            color: white;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }
        
        #quickConvertBtn:hover {
            background-color: #e67e22;
        }
        
        .instructions {
            margin-top: 40px;
            padding: 20px;
            background-color: var(--light-bg);
            border-radius: 8px;
            border: 1px solid var(--border-color);
        }
        
        .instructions h3 {
            margin-bottom: 15px;
            color: var(--primary-color);
        }
        
        .step {
            margin: 12px 0;
            padding-left: 5px;
            position: relative;
        }
        
        .step:before {
            content: "";
            position: absolute;
            left: -20px;
            top: 8px;
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background-color: var(--secondary-color);
        }
        
        .alert {
            padding: 15px;
            margin: 20px 0;
            border-radius: 6px;
            display: none;
        }
        
        .alert-success {
            background-color: rgba(46, 204, 113, 0.1);
            border: 1px solid var(--success-color);
            color: var(--success-color);
            display: block;
        }
        
        .alert-error {
            background-color: rgba(231, 76, 60, 0.1);
            border: 1px solid var(--danger-color);
            color: var(--danger-color);
            display: block;
        }
        
        .code-block {
            background-color: #f8f9fa;
            padding: 15px;
            border-radius: 6px;
            font-family: 'Consolas', 'Monaco', monospace;
            font-size: 14px;
            overflow-x: auto;
            margin: 10px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>PNG 转 ICO 工具</h1>
        <p class="intro">请选择要转换的 PNG 图像文件（推荐尺寸：16x16、32x32 或 48x48 像素）</p>
        
        <div class="file-upload">
            <label for="fileInput" class="upload-btn">选择 PNG 文件</label>
            <input type="file" id="fileInput" accept=".png">
        </div>
        
        <div id="alertContainer"></div>
        
        <div id="previewContainer">
            <img id="preview" src="" alt="预览图像">
        </div>
        
        <a id="downloadLink" href="#">下载 ICO 文件</a>
        
        <div class="quick-actions">
            <button id="quickConvertBtn" style="display: none;">快速转换当前网站的favicon</button>
        </div>
    </div>
    
    <div class="instructions">
        <h3>使用说明：</h3>
        <div class="step">1. 点击 "选择 PNG 文件" 按钮，选择您的 favicon.png 文件</div>
        <div class="step">2. 系统会自动转换并显示下载链接</div>
        <div class="step">3. 点击 "下载 ICO 文件" 保存转换后的图标</div>
        <div class="step">4. 将下载的 favicon.ico 文件上传到您的网站根目录</div>
        <div class="step">5. 在您的 HTML 页面的 &lt;head&gt; 部分添加以下代码：</div>
        <div class="code-block">&lt;link rel="icon" type="image/x-icon" href="/favicon.ico"&gt;</div>
    </div>

    <script>
        // 安全的ICO生成函数
        function createICO(images) {
            try {
                if (!images || !Array.isArray(images) || images.length === 0) {
                    throw new Error('无效的图像数据');
                }

                const header = new ArrayBuffer(6);
                const headerView = new DataView(header);
                
                // ICO 文件头
                headerView.setUint16(0, 0, true); // 保留字段，必须为0
                headerView.setUint16(2, 1, true); // 类型，1=ICO
                headerView.setUint16(4, images.length, true); // 图像数量
                
                let offset = 6 + images.length * 16; // 文件头 + 目录项
                let dataSize = offset;
                
                // 计算总数据大小
                for (const img of images) {
                    if (!img.data || !(img.data instanceof Uint8Array)) {
                        throw new Error('图像数据格式无效');
                    }
                    dataSize += img.data.length;
                }
                
                const buffer = new ArrayBuffer(dataSize);
                const view = new DataView(buffer);
                
                // 复制文件头
                new Uint8Array(buffer, 0, 6).set(new Uint8Array(header));
                
                // 写入目录项和图像数据
                for (let i = 0; i < images.length; i++) {
                    const img = images[i];
                    
                    // 验证图像尺寸
                    if (!Number.isInteger(img.width) || !Number.isInteger(img.height) || 
                        img.width <= 0 || img.width > 256 || 
                        img.height <= 0 || img.height > 256) {
                        throw new Error(`无效的图像尺寸: ${img.width}x${img.height}`);
                    }
                    
                    // 目录项
                    view.setUint8(6 + i * 16, img.width);
                    view.setUint8(6 + i * 16 + 1, img.height);
                    view.setUint8(6 + i * 16 + 2, 0); // 颜色数，0=256+色
                    view.setUint8(6 + i * 16 + 3, 0); // 保留字段
                    view.setUint16(6 + i * 16 + 4, 1, true); // 颜色平面
                    view.setUint16(6 + i * 16 + 6, 32, true); // 位深度
                    view.setUint32(6 + i * 16 + 8, img.data.length, true); // 数据大小
                    view.setUint32(6 + i * 16 + 12, offset, true); // 数据偏移量
                    
                    // 写入图像数据
                    new Uint8Array(buffer, offset, img.data.length).set(img.data);
                    offset += img.data.length;
                }
                
                return buffer;
            } catch (error) {
                console.error('ICO创建失败:', error);
                showAlert('ICO文件生成失败: ' + error.message, 'error');
                return null;
            }
        }

        // 显示提示信息
        function showAlert(message, type = 'info') {
            const alertContainer = document.getElementById('alertContainer');
            alertContainer.innerHTML = `
                <div class="alert alert-${type}">
                    ${message}
                </div>
            `;
            
            // 3秒后自动隐藏提示
            setTimeout(() => {
                alertContainer.innerHTML = '';
            }, 5000);
        }

        // 主逻辑
        document.addEventListener('DOMContentLoaded', function() {
            const fileInput = document.getElementById('fileInput');
            const preview = document.getElementById('preview');
            const downloadLink = document.getElementById('downloadLink');
            const quickConvertBtn = document.getElementById('quickConvertBtn');
            
            // 文件选择处理
            fileInput.addEventListener('change', function(e) {
                const file = e.target.files[0];
                if (!file) return;
                
                // 安全检查：验证文件类型和大小
                if (!file.type.match('image/png')) {
                    showAlert('请选择 PNG 格式的图像文件', 'error');
                    return;
                }
                
                // 限制文件大小为5MB
                if (file.size > 5 * 1024 * 1024) {
                    showAlert('文件大小不能超过5MB', 'error');
                    return;
                }
                
                const reader = new FileReader();
                reader.onload = function(event) {
                    const img = new Image();
                    
                    // 图像加载错误处理
                    img.onerror = function() {
                        showAlert('无法加载图像文件，请确保文件是有效的PNG图像', 'error');
                    };
                    
                    img.onload = function() {
                        // 验证图像尺寸
                        if (img.width > 1024 || img.height > 1024) {
                            showAlert('图像尺寸过大，建议使用16x16、32x32或48x48像素的图像', 'warning');
                        }
                        
                        // 显示预览
                        preview.src = event.target.result;
                        preview.style.display = 'block';
                        
                        // 创建canvas并绘制图像
                        const canvas = document.createElement('canvas');
                        const ctx = canvas.getContext('2d');
                        
                        // 定义要生成的尺寸
                        const sizes = [16, 32, 48];
                        const images = [];
                        let processedCount = 0;
                        
                        sizes.forEach(size => {
                            canvas.width = size;
                            canvas.height = size;
                            
                            try {
                                // 绘制图像并保留透明度
                                ctx.clearRect(0, 0, size, size);
                                ctx.drawImage(img, 0, 0, size, size);
                                
                                // 获取图像数据
                                canvas.toBlob(blob => {
                                    const reader = new FileReader();
                                    reader.onload = function() {
                                        try {
                                            const arrayBuffer = this.result;
                                            const uint8Array = new Uint8Array(arrayBuffer);
                                            
                                            images.push({
                                                width: size,
                                                height: size,
                                                data: uint8Array
                                            });
                                            
                                            processedCount++;
                                            
                                            // 当所有尺寸都处理完成后生成ICO
                                            if (processedCount === sizes.length) {
                                                generateAndDownloadICO(images);
                                            }
                                        } catch (error) {
                                            showAlert('处理图像数据时出错: ' + error.message, 'error');
                                        }
                                    };
                                    reader.readAsArrayBuffer(blob);
                                }, 'image/png');
                            } catch (error) {
                                showAlert('绘制图像时出错: ' + error.message, 'error');
                            }
                        });
                    };
                    
                    img.src = event.target.result;
                };
                
                reader.onerror = function() {
                    showAlert('文件读取失败，请重试', 'error');
                };
                
                reader.readAsDataURL(file);
            });
            
            // 生成并下载ICO文件
            function generateAndDownloadICO(images) {
                try {
                    const icoBuffer = createICO(images);
                    if (!icoBuffer) return;
                    
                    const blob = new Blob([icoBuffer], {type: 'image/x-icon'});
                    const url = URL.createObjectURL(blob);
                    
                    // 设置下载链接
                    downloadLink.href = url;
                    downloadLink.download = 'favicon.ico';
                    downloadLink.style.display = 'block';
                    
                    showAlert('图像转换成功！请点击下载按钮获取ICO文件', 'success');
                } catch (error) {
                    console.error('生成ICO文件时出错:', error);
                    showAlert('生成ICO文件时出错: ' + error.message, 'error');
                }
            }
            
            // 快速转换按钮逻辑
            if (document.location.hostname !== 'localhost' && document.location.protocol !== 'file:') {
                const testImg = new Image();
                testImg.onload = function() {
                    quickConvertBtn.style.display = 'inline-block';
                };
                
                testImg.onerror = function() {
                    console.log('未检测到favicon.png，无法提供快速转换');
                };
                
                testImg.src = '/favicon.png?' + new Date().getTime();
            }
            
            quickConvertBtn.addEventListener('click', function() {
                try {
                    const canvas = document.createElement('canvas');
                    const ctx = canvas.getContext('2d');
                    const img = new Image();
                    
                    img.crossOrigin = 'anonymous'; // 处理跨域问题
                    
                    img.onerror = function() {
                        showAlert('无法加载当前网站的favicon.png', 'error');
                    };
                    
                    img.onload = function() {
                        try {
                            // 创建16x16尺寸
                            canvas.width = 16;
                            canvas.height = 16;
                            ctx.drawImage(img, 0, 0, 16, 16);
                            
                            canvas.toBlob(blob => {
                                const url = URL.createObjectURL(blob);
                                const a = document.createElement('a');
                                a.href = url;
                                a.download = 'favicon.ico';
                                a.click();
                                URL.revokeObjectURL(url);
                                showAlert('快速转换成功！', 'success');
                            }, 'image/x-icon');
                        } catch (error) {
                            showAlert('快速转换失败: ' + error.message, 'error');
                        }
                    };
                    
                    img.src = '/favicon.png?' + new Date().getTime();
                } catch (error) {
                    showAlert('快速转换失败: ' + error.message, 'error');
                }
            });
        });
    </script>
</body>
</html>